﻿using System;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Algorithm;
using YJKGridTopologyCal.Utilities;

namespace YJKGridTopologyCal.Mathematics
{
	public class Vector2D : ICloneable
	{
		public static Vector2D Create(double x, double y)
		{
			return new Vector2D(x, y);
		}

		public static Vector2D Create(Vector2D v)
		{
			return new Vector2D(v);
		}

		public static Vector2D Create(Coordinate coord)
		{
			return new Vector2D(coord);
		}

		public static Vector2D Create(Coordinate from, Coordinate to)
		{
			return new Vector2D(from, to);
		}

		public Vector2D() : this(0.0, 0.0)
		{
		}

		public Vector2D(double x, double y)
		{
			this._x = x;
			this._y = y;
		}

		public Vector2D(Vector2D v)
		{
			this._x = v._x;
			this._y = v._y;
		}

		public Vector2D(Coordinate from, Coordinate to)
		{
			this._x = to.X - from.X;
			this._y = to.Y - from.Y;
		}

		public Vector2D(Coordinate v)
		{
			this._x = v.X;
			this._y = v.Y;
		}

		public double X
		{
			get
			{
				return this._x;
			}
		}

		public double Y
		{
			get
			{
				return this._y;
			}
		}

		public double this[int index]
		{
			get
			{
				if (index == 0)
				{
					return this._x;
				}
				if (index != 1)
				{
					throw new ArgumentOutOfRangeException("index");
				}
				return this._y;
			}
		}

		public Vector2D Add(Vector2D v)
		{
			return Vector2D.Create(this._x + v._x, this._y + v._y);
		}

		public Vector2D Subtract(Vector2D v)
		{
			return Vector2D.Create(this._x - v._x, this._y - v._y);
		}

		public Vector2D Multiply(double d)
		{
			return Vector2D.Create(this._x * d, this._y * d);
		}

		public Vector2D Divide(double d)
		{
			return Vector2D.Create(this._x / d, this._y / d);
		}

		public Vector2D Negate()
		{
			return Vector2D.Create(-this._x, -this._y);
		}

		public double Length()
		{
			return Math.Sqrt(this._x * this._x + this._y * this._y);
		}

		public double LengthSquared()
		{
			return this._x * this._x + this._y * this._y;
		}

		public Vector2D Normalize()
		{
			double num = this.Length();
			if (num > 0.0)
			{
				return this.Divide(num);
			}
			return Vector2D.Create(0.0, 0.0);
		}

		public Vector2D Average(Vector2D v)
		{
			return this.WeightedSum(v, 0.5);
		}

		public Vector2D WeightedSum(Vector2D v, double frac)
		{
			return Vector2D.Create(frac * this._x + (1.0 - frac) * v._x, frac * this._y + (1.0 - frac) * v._y);
		}

		public double Distance(Vector2D v)
		{
			double num = v._x - this._x;
			double num2 = v._y - this._y;
			return Math.Sqrt(num * num + num2 * num2);
		}

		public double Dot(Vector2D v)
		{
			return this._x * v._x + this._y * v._y;
		}

		public double Angle()
		{
			return Math.Atan2(this._y, this._x);
		}

		public double Angle(Vector2D v)
		{
			return AngleUtility.Diff(v.Angle(), this.Angle());
		}

		public double AngleTo(Vector2D v)
		{
			double num = this.Angle();
			double num2 = v.Angle() - num;
			if (num2 <= -Math.PI)
			{
				return num2 + Math.PI*2;
			}
			if (num2 > Math.PI)
			{
				return num2 - Math.PI*2;
			}
			return num2;
		}

		public Vector2D Rotate(double angle)
		{
			double num = Math.Cos(angle);
			double num2 = Math.Sin(angle);
			return Vector2D.Create(this._x * num - this._y * num2, this._x * num2 + this._y * num);
		}

		public Vector2D RotateByQuarterCircle(int numQuarters)
		{
			int num = numQuarters % 4;
			if (numQuarters < 0 && num != 0)
			{
				num += 4;
			}
			switch (num)
			{
			case 0:
				return Vector2D.Create(this._x, this._y);
			case 1:
				return Vector2D.Create(-this._y, this._x);
			case 2:
				return Vector2D.Create(-this._x, -this._y);
			case 3:
				return Vector2D.Create(this._y, -this._x);
			default:
				Assert.ShouldNeverReachHere();
				return null;
			}
		}

		public bool IsParallel(Vector2D v)
		{
			return 0.0 == (double)RobustDeterminant.SignOfDet2x2(this._x, this._y, v._x, v._y);
		}

		public Coordinate Translate(Coordinate coord)
		{
			return new Coordinate(this._x + coord.X, this._y + coord.Y);
		}

		public Coordinate ToCoordinate()
		{
			return new Coordinate(this._x, this._y);
		}

		public object Clone()
		{
			return new Vector2D(this);
		}

		public override string ToString()
		{
			return string.Concat(new object[]
			{
				"[",
				this._x,
				", ",
				this._y,
				"]"
			});
		}

		public override bool Equals(object o)
		{
			if (!(o is Vector2D))
			{
				return false;
			}
			Vector2D vector2D = (Vector2D)o;
			return this._x == vector2D._x && this._y == vector2D._y;
		}

		public override int GetHashCode()
		{
			int num = 17;
			num = 37 * num + Coordinate.GetHashCode(this._x);
			return 37 * num + Coordinate.GetHashCode(this._y);
		}

		private readonly double _x;

		private readonly double _y;
	}
}
